package com.szt.sy.aspect;

import java.lang.reflect.Method;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.InputStreamSource;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.szt.sy.anontation.SysLog;
import com.szt.sy.entity.system.SysLogRecord;
import com.szt.sy.service.system.syslog.SysLogService;
import com.szt.sy.util.json.JsonUtils;
import com.szt.sy.util.web.IpUtils;

/***
 * 系统日志切面
 * 
 * @author wwy
 *
 */
@Aspect
@Component
public class SysLogAspect {
	
	@Autowired
	private SysLogService sysLogService;
	
	private ThreadLocal<SysLogRecord> sysLogRecordMap = new ThreadLocal<>();
	
	/***
	 * 返回信息最大长度
	 */
	private static final Integer MAX_RESPONSE_LENGTH = 1000;
	
	/***
	 * {@code @Pointcut("execution(public * com.szt.sy.controller.sy..*.*(..)) ||execution(public * com.szt.sy.controller.system..*.*(..))")}
	 */
	@Pointcut("@annotation(com.szt.sy.anontation.SysLog)")
	public void webLog() {
	}
	
	@Before("webLog()")
	public void doBefore(JoinPoint joinPoint) {
		try {
			// 接收到请求，记录请求内容
			ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder
					.getRequestAttributes();
			HttpServletRequest request = attributes.getRequest();
			MethodSignature signature = (MethodSignature) joinPoint.getSignature();
			Method method = signature.getMethod();
			SysLogRecord sysLogRecord = new SysLogRecord();
			SysLog syslog = method.getAnnotation(SysLog.class);
			if (syslog != null) {
				// 注解上的描述
				sysLogRecord.setOperation(syslog.value());
			}
			// 记录下请求内容
			sysLogRecord.setIp(IpUtils.getIpAddr(request));
			sysLogRecord.setMethod(joinPoint.getSignature().getDeclaringTypeName() + "."
					+ joinPoint.getSignature().getName() + ":" + request.getMethod());
			// 记录请求参数
			Object[] args = joinPoint.getArgs();
			if (args != null && args.length > 0) {
				StringBuffer paramsBuffer = new StringBuffer();
				for (int i = 0; i < args.length; i++) {
					Object arg = args[i];
					if (arg instanceof HttpSession) {
						paramsBuffer.append("param[").append(i).append("]:httpsession,");
					} else if (arg instanceof HttpServletRequest) {
						paramsBuffer.append("param[").append(i).append("]:HttpServletRequest,");
					} else if (arg instanceof HttpServletResponse) {
						paramsBuffer.append("param[").append(i).append("]:HttpServletResponse,");
					} else if (arg instanceof InputStreamSource) {
						paramsBuffer.append("param[").append(i).append("]:file,");
					} else {
						paramsBuffer.append("param[").append(i).append("]:").append(JsonUtils.beanToString(arg))
								.append(",");
					}
				}
				sysLogRecord.setParams(paramsBuffer.toString());
			}
			sysLogRecord.setTime(System.currentTimeMillis());
			sysLogRecord.setUserId(MDC.get("userId"));
			sysLogRecord.setUsername(MDC.get("username"));
			sysLogRecordMap.set(sysLogRecord);
		} catch (Exception e) {
		}
		
	}
	
	@AfterReturning(returning = "ret", pointcut = "webLog()")
	public void doAfterReturning(Object ret) throws Throwable {
		try {
			SysLogRecord sysLogRecord = sysLogRecordMap.get();
			sysLogRecordMap.remove();
			String response = JsonUtils.beanToString(ret);
			if (response.length() < MAX_RESPONSE_LENGTH) {
				sysLogRecord.setResponse(JsonUtils.beanToString(ret));
			}
			sysLogRecord.setTime(System.currentTimeMillis() - sysLogRecord.getTime());
			sysLogService.insert(sysLogRecord);
			
		} catch (Exception e) {
		}
		
	}
}